﻿using DevExpress.Data.Filtering;
using Newtonsoft.Json;
using System.Linq.Dynamic.Core;
using System.Threading.Channels;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using Volo.Abp.Security.Encryption;
using Volo.Abp.Uow;
using YAPACS.BusinessObjects.Exams;
using YAPACS.BusinessObjects.Managements.Devices;
using YAPACS.BusinessObjects.Managements.Exams;
using YAPACS.BusinessObjects.Services;
using YAPACS.Organizations;
using YAPACS.RisServer.Abstractions;
using YAPACS.RisServer.Services.Dtos;
using YAPACS.RisServer.Workflows.Technician;
using YAPACS.Workflows;

namespace YAPACS.RisServer.Services;

public class TechnicianService(IUnitOfWorkManager unitOfWorkManager, IRepository<Exam, Guid> examRepository,
    IGetAdvancedSearchView getAdvancedSearchView, IRepository<Device, Guid> deviceRepository, IRepository<ExamQueuing, Guid> examQueuingRepository,
    IGetHeaders getHeaders, IGetRowStyle getRowStyle, ICall call, IChangeDevice changeDevice, IGetEmergencyRegistView getEmergencyRegisterView,
    IEnd end, IGetCheckParameterRecordView getCheckParameterRecordView, IGetRecheckView getRecheckView, IStart start, IGetViewApply getViewApply,
    IGetToolBarExtension getToolBarExtension, IAdvancedSearchExpression advancedSearchExpression, IGetDefaultFilter getDefaultFilter,
    IRepository<ApplicationUser, Guid> userRepository, ICurrentUserOrganization currentUserOrganization, IExamListService examListService,
    ICancel cancel, IPass pass, IStationCodeProvider stationCodeProvider, IExamPermissionService examPermissionService, IExamEventService examEventService,
    IExportService exportService, IStringEncryptionService stringEncryptionService, IAccountVerifyService accountVerifyService, IRepository<Department, Guid> departmentRepository)
    : DomainService, ITechnicianService, ITransientDependency
{
    private readonly IUnitOfWorkManager _unitOfWorkManager = unitOfWorkManager;
    private readonly ICurrentUserOrganization _currentUserOrganization = currentUserOrganization;
    private readonly IRepository<Exam, Guid> _examRepository = examRepository;
    private readonly IRepository<Device, Guid> _deviceRepository = deviceRepository;
    private readonly IRepository<ExamQueuing, Guid> _examQueuingRepository = examQueuingRepository;
    private readonly IRepository<Department, Guid> _departmentRepository = departmentRepository;

    private readonly IGetAdvancedSearchView _getAdvancedSearchView = getAdvancedSearchView;
    private readonly IGetHeaders _getHeaders = getHeaders;
    private readonly IGetRowStyle _getRowStyle = getRowStyle;
    private readonly ICall _call = call;
    private readonly ICancel _cancel = cancel;
    private readonly IChangeDevice _changeDevice = changeDevice;
    private readonly IGetEmergencyRegistView _getEmergencyRegisterView = getEmergencyRegisterView;
    private readonly IEnd _end = end;
    private readonly IGetCheckParameterRecordView _getCheckParameterRecordView = getCheckParameterRecordView;
    private readonly IGetToolBarExtension _getToolBarExtension = getToolBarExtension;
    private readonly IGetRecheckView _getRecheckView = getRecheckView;
    private readonly IStart _start = start;
    private readonly IGetViewApply _getViewApply = getViewApply;
    private readonly IAdvancedSearchExpression _advancedSearchExpression = advancedSearchExpression;
    private readonly IGetDefaultFilter _getDefaultFilter = getDefaultFilter;
    private readonly IRepository<ApplicationUser, Guid> _userRepository = userRepository;
    private readonly IExamListService _examListService = examListService;
    private readonly IPass _pass = pass;
    private readonly IStationCodeProvider _stationCodeProvider = stationCodeProvider;
    private readonly IExamPermissionService _examPermissionService = examPermissionService;
    private readonly IExamEventService _examEventService = examEventService;
    private readonly IExportService _exportService = exportService;
    private readonly IStringEncryptionService _stringEncryptionService = stringEncryptionService;
    private readonly IAccountVerifyService _accountVerifyService = accountVerifyService;

    public async Task<WorkflowOutput> CallAsync(Guid examId)
    {
        try
        {
            var exam = await _examRepository.GetAsync(examId);
            await _examPermissionService.ValidateAsync(exam);

            if (exam.ExamQueuing != null)
            {
                var startTime = Clock.Now.Date;
                var endTime = Clock.Now.Date.AddDays(1);

                if (!(exam.ExamQueuing.StartTime >= startTime && exam.ExamQueuing.StartTime < endTime))
                {
                    throw new Exception("当前不是今天的检查");
                }

                if (exam.ExamQueuing.Status != ExamQueuingStatus.Wait && exam.ExamQueuing.Status != ExamQueuingStatus.Ready)
                {
                    throw new Exception("当前不是等候的检查");
                }
            }
            else
            {
                throw new Exception("当前患者没有到诊");
            }

            if (exam.ExamDevice != null)
            {
                //if (exam.ExamDevice.Station.Code != stationCode)
                //{
                //    throw new Exception("当前不是本站点的检查");
                //}
            }
            else if (exam.ExamCategory != null)
            {
                var stationCode = _stationCodeProvider.GetStationCode();
                if (string.IsNullOrEmpty(stationCode))
                {
                    throw new Exception("没有绑定的站点无法呼叫");
                }

                var device = await _deviceRepository.FirstOrDefaultAsync(d => d.DeviceType == exam.ExamCategory.DeviceType && d.Station.Code == stationCode && d.IsActive);
                if (device == null)
                {
                    throw new Exception("本站点不支持当前的检查类型");
                }
                else
                {
                    exam.ExamDevice = device;
                }
            }

            var workflowOutput = await _call.InvokeAsync(new WorkflowInput { { "Exam", exam } });
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> CallNextAsync()
    {
        try
        {
            var today = Clock.Now.Date;
            var hour = Clock.Now.Hour;

            var startTime = today;
            var endTime = hour < 13 ? today.AddHours(12) : today.AddDays(1);

            var stationCode = _stationCodeProvider.GetStationCode();
            if (string.IsNullOrEmpty(stationCode))
            {
                throw new Exception("没有绑定的站点无法呼叫");
            }

            var devices = await _deviceRepository.GetListAsync(d => d.Station.Code == stationCode && d.IsActive);
            var categories = devices.SelectMany(d => d.ExamCategories).Distinct().ToList();

            var query = await _examQueuingRepository.GetQueryableAsync();
            query = query.Where(e => e.Status == ExamQueuingStatus.Wait);
            query = query.Where(e => e.StartTime >= startTime && e.EndTime < endTime);
            query = query.Where(e =>
                (e.Exam.ExamDevice != null && devices.Contains(e.Exam.ExamDevice)) ||
                (e.Exam.ExamCategory != null && categories.Contains(e.Exam.ExamCategory))
            );

            var queuingList = await AsyncExecuter.ToListAsync(query.OrderBy(e => e.Order).Take(2));
            if (queuingList.Count == 0)
            {
                return new WorkflowOutput
                {
                    Success = false,
                    Error = "已没有等待的检查"
                };
            }

            var exam = queuingList.First().Exam;

            var workflowOutput = await _call.InvokeAsync(new WorkflowInput
            {
                { "Exam", exam },
                { "Exams", queuingList.Select(q => q.Exam).ToList() },
                { "CallNext", true }
            });

            return workflowOutput;
        }
        catch (Exception ex)
        {
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> CancelExamAsync(WorkflowInput input, string nextApi = null)
    {
        try
        {
            var examId = Guid.Parse(input.GetValueOrDefault("examId")?.ToString());
            var exam = await _examRepository.GetAsync(examId);
            await _examPermissionService.ValidateAsync(exam);
            var userName = input.GetValueOrDefault("userName")?.ToString();
            var password = input.GetValueOrDefault("password")?.ToString();
            if (string.IsNullOrWhiteSpace(userName))
            {
                var workflowOutput = await _accountVerifyService.GetVerifyViewAsync();
                if (!string.IsNullOrWhiteSpace(nextApi))
                {
                    workflowOutput.NextApi = nextApi;
                }
                return workflowOutput;
            }
            else
            {
                var workflowOutput = await _accountVerifyService.VerifyAsync(userName, password, "技师_取消检查", exam);
                if (workflowOutput.Success)
                {
                    workflowOutput = await _cancel.InvokeAsync(new WorkflowInput { { "Input", input } });
                }
                return workflowOutput;
            }
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> ChangeDeviceAsync(Guid examId, Guid deviceId)
    {
        try
        {
            var exam = await _examRepository.GetAsync(examId);
            await _examPermissionService.ValidateAsync(exam);
            var device = await _deviceRepository.GetAsync(deviceId);
            var input = new WorkflowInput {
                { "Exam", exam },
                { "Device",device}
            };
            var workflowOutput = await _changeDevice.InvokeAsync(input);
            var oldDevice = exam.ExamDevice;
            exam.ExamDevice = device;
            await _examEventService.AddExamEventAsync(exam, "更换设备", $"原设备：{oldDevice?.CompoundName}，新设备：{device?.CompoundName}");
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> CheckParameterRecordAsync(Guid examId)
    {
        try
        {
            var exam = await _examRepository.GetAsync(examId);
            await _examPermissionService.ValidateAsync(exam);
            var workflowOutput = await _getCheckParameterRecordView.InvokeAsync(new WorkflowInput { { "Exam", exam } });
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> EmergencyRegisterAsync()
    {
        try
        {
            const string key = "Output";
            var input = new WorkflowInput();
            var workflowOutput = await _getEmergencyRegisterView.InvokeAsync(input);
            if (input.ContainsKey(key) && input.GetValueOrDefault(key) is Exam exam)
            {
                //处理逻辑
            }
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> CompletedAsync(Guid examId)
    {
        try
        {
            var exam = await _examRepository.GetAsync(examId);
            await _examPermissionService.ValidateAsync(exam);
            var workflowOutput = await _end.InvokeAsync(new WorkflowInput { { "Exam", exam } });
            if (exam.ExamStatus < ExamStatus.Report)
            {
                exam.ExamStatus = ExamStatus.Report;
            }
            exam.ExamQueuing.Status = ExamQueuingStatus.Completed;
            exam.ExamTime ??= Clock.Now;
            //检查技师
            exam.ExamOperator ??= await _userRepository.GetAsync(_currentUserOrganization.UserId);

            await _examEventService.AddExamEventAsync(exam, "完成检查");

            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> GetAdvancedSearchViewAsync()
    {
        try
        {
            var workflowOutput = await _getAdvancedSearchView.InvokeAsync([]);
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> GetExamListByFilterAsync(DataGridRequest request)
    {
        try
        {
            //获取查询表达式
            CriteriaOperator criteriaOperator = CriteriaOperator.FromLambda<Exam>(e => e.ExamStatus > ExamStatus.Appointment);
            var result = await _examListService.GetListByFilterAsync(request, criteriaOperator, _advancedSearchExpression, _getHeaders, _getRowStyle,
                _getDefaultFilter, ExamFilterType.Queuing);
            return result;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput()
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> GetToolBarExtensionAsync()
    {
        try
        {
            var workflowOutput = await _getToolBarExtension.InvokeAsync(new WorkflowInput());
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public Task<WorkflowOutput> OpenExamAsync(Guid examId)
    {
        throw new NotImplementedException();
    }

    public async Task<WorkflowOutput> RecheckAsync(Guid examId)
    {
        try
        {
            var exam = await _examRepository.GetAsync(examId);
            await _examPermissionService.ValidateAsync(exam);
            var workflowOutput = await _getRecheckView.InvokeAsync(new WorkflowInput { { "Exam", exam } });
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> StartAsync(Guid examId)
    {
        try
        {
            var exam = await _examRepository.GetAsync(examId);
            await _examPermissionService.ValidateAsync(exam);
            if (exam.ExamStatus == ExamStatus.Cancellation)
            {
                throw new Exception("被取消的检查无法再次进行检查");
            }
            var workflowOutput = await _start.InvokeAsync(new WorkflowInput { { "Exam", exam } });
            if (exam.ExamStatus < ExamStatus.Exam)
            {
                exam.ExamStatus = ExamStatus.Exam;
            }
            if (exam.ExamDepartment == null)
            {
                exam.ExamDepartment = await _departmentRepository.GetAsync(_currentUserOrganization.DepartmentId.Value);
            }
            exam.ExamQueuing.Status = ExamQueuingStatus.Check;
            exam.ExamTime ??= Clock.Now;
            //检查技师
            exam.ExamOperator = await _userRepository.GetAsync(_currentUserOrganization.UserId);

            await _examEventService.AddExamEventAsync(exam, "开始检查");

            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> ViewApplyAsync(Guid examId)
    {
        try
        {
            var exam = await _examRepository.GetAsync(examId);
            var workflowOutput = await _getViewApply.InvokeAsync(new WorkflowInput { { "Exam", exam } });
            if (!workflowOutput.Success)
            {
                throw new Exception(workflowOutput.Error);
            }
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> PassAsync(Guid examId)
    {
        try
        {
            var exam = await _examRepository.GetAsync(examId);
            await _examPermissionService.ValidateAsync(exam);
            var workflowOutput = await _pass.InvokeAsync(new WorkflowInput { { "Exam", exam } });
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> ExportAsync(DataGridRequest request)
    {
        try
        {
            CriteriaOperator criteriaOperator = CriteriaOperator.FromLambda<Exam>(e => e.ExamStatus > ExamStatus.Appointment);
            var file = await _exportService.ExportListToFileAsync(request, criteriaOperator, _advancedSearchExpression, _getHeaders, _getDefaultFilter, ExamFilterType.Queuing);
            if (File.Exists(file))
            {
                return new WorkflowOutput()
                {
                    Success = true,
                    Data = _stringEncryptionService.Encrypt(Path.GetFileName(file)),
                };
            }
            else
            {
                return new WorkflowOutput()
                {
                    Success = false,
                    Error = "导出列表失败，请稍后重试"
                };
            }
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput()
            {
                Success = false,
                Error = ex.Message
            };
        }
    }
}
